<?php

namespace api\modules\v1\forms\rbac;

use common\models\member\Member;
use common\models\rbac\Role;
use common\models\rbac\RolePermission;
use services\rbac\ActionService;
use services\rbac\MenuService;
use services\rbac\RolePermissionService;
use services\rbac\MemberRoleService;
use Yii;
use yii\base\Model;

/**
 * Class RoleForm
 * @package api\modules\v1\forms\rbac
 */
class RoleForm extends Model
{
    /**
     * @var int $id 角色ID
     * @var string $name 角色名
     * @var string $desc 角色描述
     * @var int $type 角色类型
     * @var int $status 状态
     * @var int $sort 排序
     * @var array $menu_ids 菜单IDs
     * @var array $action_ids 动作IDs
     */
    public $id;
    public $name;
    public $desc;
//    public $project_id;
    public $status;
    public $type;
    public $sort;
    public $menu_ids;
    public $action_ids;
//    public $module_ids;

    /**
     * @var Role $_role 角色信息
     * @var array $_rolePermissionList 角色权限
     * @var array $_deleteMenuIds 删除菜单权限IDs
     * @var array $_addMenuIds 新增菜单权限IDs
     * @var array $_deleteActionIds 删除动作权限IDs
     * @var array $_addActionIds 新增动作权限IDs
     * @var array $_hasPermissionList 当前用户绑定角色权限
     */
    protected $_role;
    protected $_rolePermissionList;
    protected $_deleteMenuIds = [];
    protected $_addMenuIds = [];
    protected $_deleteActionIds = [];
    protected $_addActionIds = [];
    protected $_hasRolePermissionList;


    public function rules()
    {
        return [
            // 参数验证
            [['name', 'status', 'type'], 'required', 'message' => '{attribute}不能为空', 'on' => ['create']],
            [['id', 'name'], 'required', 'message' => '{attribute}不能为空', 'on' => ['edit']],
            [['id'], 'required', 'message' => '{attribute}不能为空', 'on' => ['delete']],
            [['id', 'status'], 'required', 'message' => '{attribute}不能为空', 'on' => ['edit_status']],

//            [['project_id'], 'checkProjectId', 'skipOnEmpty' => false, 'on' => ['create', 'edit', 'delete', 'edit_status']],
            [['id'], 'checkId', 'skipOnEmpty' => false, 'on' => ['edit', 'edit_permission', 'delete', 'edit_status']],
            [['name'], 'checkName', 'skipOnEmpty' => false, 'on' => ['create', 'edit']],
            [['desc'], 'checkDesc', 'skipOnEmpty' => true, 'on' => ['create', 'edit']],
            [['status'], 'checkStatus', 'skipOnEmpty' => false, 'on' => ['create', 'edit', 'edit_status']],
//            [['type'], 'checkType', 'skipOnEmpty' => false, 'on' => ['create']],
            [['menu_ids'], 'checkMenuIds', 'skipOnEmpty' => false, 'on' => ['edit_permission']],
            [['action_ids'], 'checkActionIds', 'skipOnEmpty' => false, 'on' => ['edit_permission']],
//            [['module_ids'], 'checkModuleIds', 'skipOnEmpty' => false, 'on' => ['create', 'edit']],
        ];
    }

    public function scenarios()
    {
        $scenarios = parent::scenarios();

        // 新增
        $scenarios['create'] = ['name', 'desc', 'status'];

        // 编辑
        $scenarios['edit'] = ['id', 'name', 'desc', 'status'];

        // 删除
        $scenarios['delete'] = ['id', 'project_id'];

        // 编辑角色状态
        $scenarios['edit_status'] = ['id', 'status'];

        // 编辑角色状态
        $scenarios['edit_permission'] = ['id', 'menu_ids', 'action_ids'];

        return $scenarios;
    }

    /**
     * @return array
     */
    public function attributeLabels()
    {
        return [
            'id' => '角色ID',
            'name' => '角色名称',
            'desc' => '角色说明',
            'project_id' => '项目ID',
            'status' => '状态',
            'type' => '类型',
            'menu_ids' => '菜单IDs',
            'action_ids' => '动作IDs',
//            'module_ids' => '模块IDs',
        ];
    }

    /**
     * 检验角色ID
     * @param $attribute
     * @return void
     */
    public function checkId($attribute): void
    {
        if ($this->hasErrors()) {
            return;
        }

        $role = $this->getRole();
        if (!$role) {
            $this->addError($attribute, '角色不存在');
            return;
        }

        if ($role->status == Role::STATUS_DELETE) {
            $this->addError($attribute, '角色已删除，无法操作');
            return;
        }
    }

    /**
     * 校验角色名称
     * @param $attribute
     * @return void
     */
    public function checkName($attribute): void
    {
        if ($this->hasErrors()) {
            return;
        }

        $len = mb_strlen($this->name);
        if ($len > 30) {
            $this->addError($attribute, '角色名称过长，最多30个字');
            return;
        }

        // 是否检验
        $isCheck = true;
        if ($this->getScenario() == 'edit') {
            $role = $this->getRole();
            // 角色参数未改变or系统角色【跳过】
            if ($role->name == $this->name) {
                $isCheck = false;
            }
        }

        if ($isCheck) {
            $checkRole = Role::find()
                ->where([
                    'name' => $this->name,
                    'status' => [Role::STATUS_INVALID, Role::STATUS_ENABLE]
                ])
                ->one();

            if ($checkRole) {
                $this->addError($attribute, "角色【{$this->name}】已存在");
                return;
            }
        }
    }

    /**
     * 校验角色说明
     * @param $attribute
     * @return void
     */
    public function checkDesc($attribute): void
    {
        if ($this->hasErrors()) {
            return;
        }

        $len = mb_strlen($this->desc);
        if ($len > 150) {
            $this->addError($attribute, '角色说明过长，最多150个字');
            return;
        }
    }

    /**
     * 校验角色状态
     * @param $attribute
     * @return void
     */
    public function checkStatus($attribute): void
    {
        if ($this->hasErrors()) {
            return;
        }

        if (!in_array($this->status, [Role::STATUS_INVALID, Role::STATUS_ENABLE])) {
            $this->addError($attribute, "非法状态");
            return;
        }
    }

    /**
     * 校验角色类型
     * @param $attribute
     * @return void
     */
    public function checkType($attribute): void
    {
        if ($this->hasErrors()) {
            return;
        }

        if (!in_array($this->type, [Role::TYPE_NORMAL, Role::TYPE_SYSTEM])) {
            $this->addError($attribute, "角色类型错误");
            return;
        }
    }

    /**
     * 校验菜单IDs
     * @param $attribute
     * @return void
     */
    public function checkMenuIds($attribute): void
    {
        // 菜单列表信息
        $menuList = MenuService::getEnableListByIds($this->menu_ids);
        $hasMenuIds = array_column($menuList, 'id');

        // 权限列表
//        if ($this->getScenario() == 'create') {
//            $roleMenuIds = [];
//        } else {
            $rolePermission = $this->getRolePermissionList();
            $roleMenuIds = $rolePermission['menu'];
//        }
        // 删除菜单权限IDs
        $this->_deleteMenuIds = array_diff($roleMenuIds, $hasMenuIds);
        // 新增菜单权限IDs
        $this->_addMenuIds = array_diff($hasMenuIds, $roleMenuIds);
        // 验证是否越权【非自己权限数据无法修改】
        if (Yii::$app->user->identity->member->super_type != Member::SUPER_TYPE_SUPER_ADMIN) {
            $hasRolePermission = $this->getHasRolePermissionList();
            if (array_diff($this->_deleteMenuIds, $hasRolePermission['menu'])) {
                $this->addError($attribute, "删除菜单权限已越权，无法操作");
                return;
            }
            if (array_diff($this->_addMenuIds, $hasRolePermission['menu'])) {
                $this->addError($attribute, "新增菜单权限已越权，无法操作");
                return;
            }
        }
    }

    /**
     * 校验动作IDs
     * @param $attribute
     */
    public function checkActionIds($attribute)
    {
        // 菜单列表信息
        $actionList = ActionService::getEnableListByIds($this->action_ids);
        $hasActionIds = array_column($actionList, 'id');

        // 权限列表
//        if ($this->getScenario() == 'create') {
//            $roleActionIds = [];
//        } else {
            $rolePermission = $this->getRolePermissionList();
            $roleActionIds = $rolePermission['action'];
//        }
        // 删除菜单权限IDs
        $this->_deleteActionIds = array_diff($roleActionIds, $hasActionIds);
        // 新增菜单权限IDs
        $this->_addActionIds = array_diff($hasActionIds, $roleActionIds);
        // 验证是否越权【非自己权限数据无法修改】
        if (Yii::$app->user->identity->member->super_type != Member::SUPER_TYPE_SUPER_ADMIN) {
            $hasRolePermission = $this->getHasRolePermissionList();
            if (array_diff($this->_deleteActionIds, $hasRolePermission['action'])) {
                $this->addError($attribute, "删除动作权限已越权，无法操作");
                return;
            }
            if (array_diff($this->_addActionIds, $hasRolePermission['action'])) {
                $this->addError($attribute, "新增动作权限已越权，无法操作");
                return;
            }
        }
    }

    /**
     * 校验模块IDs
     * @param $attribute
     */
//    public function checkModuleIds($attribute)
//    {
//        // 模块列表信息
//        $moduleIds = $this->module_ids ? array_unique(explode(',', $this->module_ids)) : [];
//        $moduleList = Module::find()
//            ->where(['id' => $moduleIds])
//            ->asArray()
//            ->all();
//        foreach ($moduleList as $row) {
//            if ($row['status'] != \common\models\rbac\Action::STATUS_ENABLE) {
//                $this->addError($attribute, "模块状态异常");
//                return true;
//            }
//        }
//        $hasModuleIds = array_column($moduleList, 'id');
//
//        // 权限列表
//        if ($this->getScenario() == 'create') {
//            $roleModuleIds = [];
//        } else {
//            $rolePermission = $this->getRolePermissionList();
//            $roleModuleIds = array_column($rolePermission['module'], 'permission_id');
//        }
//
//        // 删除模块权限IDs
//        $this->_deleteModuleIds = array_diff($roleModuleIds, $hasModuleIds);
//
//        // 交集，存在部分
//        $hasIds = array_intersect($roleModuleIds, $hasModuleIds);
//
//        // 新增模块权限IDs
//        $this->_addModuleIds = array_diff($hasModuleIds, $hasIds);
//    }

    /**
     * 获取角色权限
     * @return array
     */
    public function getRolePermissionList(): array
    {
        if (is_null($this->_rolePermissionList)) {
            $role = $this->getRole();

            // 角色权限
            $menuList = RolePermissionService::getMenuList([$role->id]);
            $actionList = RolePermissionService::getActionList([$role->id]);
            $this->_rolePermissionList = [
                'menu' => $menuList ? array_column($menuList, 'id') : [],
                'action' => $actionList ? array_column($actionList, 'id') : [],
            ];
        }

        return $this->_rolePermissionList;
    }


    /**
     * 获取当前用户绑定角色权限
     * @return array
     */
    public function getHasRolePermissionList(): array
    {
        if (is_null($this->_hasRolePermissionList)) {
            $menuList = $actionList = null;
            if (Yii::$app->user->identity->member->super_type != Member::SUPER_TYPE_SUPER_ADMIN) {
                // 获取用户绑定角色
                $hasRoleIds = MemberRoleService::getUserRoleEnableIds(Yii::$app->user->identity->member_id);
                $menuList = RolePermissionService::getMenuList($hasRoleIds);
                $actionList = RolePermissionService::getActionList($hasRoleIds);
//                $diffMenuIds = array_diff($roleMenuIds, $hasMenuIds);
//                $diffActionIds = array_diff($roleActionIds, $hasActionIds);
            }
            // 角色权限
            $this->_hasRolePermissionList = [
                'menu' => $menuList ? array_column($menuList, 'id') : [],
                'action' => $actionList ? array_column($actionList, 'id') : [],
            ];
        }

        return $this->_hasRolePermissionList;
    }

    /**
     * 获取删除菜单权限IDs
     * @return array
     */
    public function getDeleteMenuIds(): array
    {
        return $this->_deleteMenuIds;
    }

    /**
     * 获取新增菜单权限IDs
     * @return array
     */
    public function getAddMenuIds(): array
    {
        return $this->_addMenuIds;
    }

    /**
     * 获取删除动作权限IDs
     * @return array
     */
    public function getDeleteActionIds(): array
    {
        return $this->_deleteActionIds;
    }

    /**
     * 获取新增动作权限IDs
     * @return array
     */
    public function getAddActionIds(): array
    {
        return $this->_addActionIds;
    }

    /**
     * 获取角色信息
     * @return Role|null
     */
    public function getRole(): ?Role
    {
        if (empty($this->_role)) {
            $this->_role = Role::findOne($this->id);
        }

        return $this->_role;
    }
}
